package com.bytz.modules.cms.product.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bytz.common.constant.CommonConstant;
import com.bytz.common.exception.BytzBootException;
import com.bytz.common.system.base.service.impl.AbstractCrudService;
import com.bytz.common.system.query.MPJLambdaWrapperEx;
import com.bytz.common.system.query.MPJQueryGenerator;
import com.bytz.common.util.mentity.EntityMergeInfoV2;
import com.bytz.common.util.mentity.util.MergeEntityOptions;
import com.bytz.common.util.mentity.util.MergeEntityUtil;
import com.bytz.modules.cms.common.util.ExcelUtil;
import com.bytz.modules.cms.domain.manager.CmsManager;
import com.bytz.modules.cms.domain.manager.CmsManagerWithoutResellerDiscount;
import com.bytz.modules.cms.domain.model.price.PriceComputeResult;
import com.bytz.modules.cms.product.constant.ProductConstants;
import com.bytz.modules.cms.product.entity.Product;
import com.bytz.modules.cms.product.entity.ProductDiscountCategory;
import com.bytz.modules.cms.product.entity.ProductHierarchy;
import com.bytz.modules.cms.product.mapper.ProductMapper;
import com.bytz.modules.cms.product.model.ProductExcel;
import com.bytz.modules.cms.product.model.ProductModel;
import com.bytz.modules.cms.product.model.ProductModelExcel;
import com.bytz.modules.cms.product.service.*;
import com.bytz.modules.cms.productLine.entity.ProductLine;
import com.bytz.modules.cms.productLine.service.IProductLineService;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class AdminProductServiceImpl extends AbstractCrudService<ProductMapper, Product, Product> implements IAdminProductService {


    @Autowired
    private CmsManagerWithoutResellerDiscount cmsManager;

    @Autowired
    private CmsManager resellerCmsManager;

    @Autowired
    private IProductLineService lineService;

    @Autowired
    private IProductDiscountCategoryService discountCategoryService;

    @Autowired
    private IEcProductService ecProductService;

    @Autowired
    private IProductChangeService productChangeService;

    @Autowired
    private IProductHierarchyService productHierarchyService;

    @Override
    public List<ProductModel> getPriceByResellerId(String resellerId, List<Product> productList) {

        List<ProductModel> modelList = BeanUtil.copyToList(productList, ProductModel.class);

        Map<String, PriceComputeResult> priceResult = cmsManager.getProductPriceManager().compute(resellerId, productList);
        for (ProductModel productModel : modelList) {
            PriceComputeResult price = priceResult.get(productModel.getProductNumber());
            if (price != null) {
                productModel.setCalculatePrice(price.getPrice());
            }
        }

        return modelList;
    }

    @Override
    public BigDecimal getPriceByResellerIdAndProductId(String resellerId, String productId) {
        ArrayList<Product> products = Lists.newArrayList(getById(productId));
        // 计算经销商除去专属优惠以外的优惠价格
        Map<String, PriceComputeResult> compute = cmsManager.getProductPriceManager().compute(resellerId, products);
        PriceComputeResult result = compute.values().stream().findFirst().orElseThrow(() -> new BytzBootException("找不到商品"));
        return result.getPrice();
    }

    @Override
    public List<Product> getPriceNotNull() {
        return lambdaQuery()
                .isNotNull(Product::getBasePrice)
                .list();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean mergeProduct(List<ProductExcel> productExcels) {

        List<ProductExcel> insertOrUpdateExcels = productExcels.stream()
                .filter(excel -> !CommonConstant.DEL_FLAG_1.equals(excel.getDelFlag()))
                .collect(Collectors.toList());

        for (int i = 0; i < insertOrUpdateExcels.size(); i++) {
            ProductExcel excel = insertOrUpdateExcels.get(i);
            if (StringUtils.isBlank(excel.getProductNumber()) ||
                    StringUtils.isBlank(excel.getMaterialDesc()) ||
                    StringUtils.isBlank(excel.getProductLineCode()) ||
                    StringUtils.isBlank(excel.getHierarchyNumber()) ||
                    excel.getBasePrice() == null ||
                    excel.getCostPrice() == null ||
                    excel.getDeliveryDate() == null ||
                    excel.getDeliveryDate() <= 0 ||
                    excel.getMaxOrderQuantity() == null ||
                    StringUtils.isBlank(excel.getStatus())
            ) {
                throw new BytzBootException("第" + (i + 1) + "行数据有误");
            }
        }

        // 商品导入时：没有找到对应的商品大类等关键信息，则提示本次导入的商品有问题；需要检查商品的正确性并重导
        Set<String> hierarchyNumbers = insertOrUpdateExcels.stream().map(ProductExcel::getHierarchyNumber).collect(Collectors.toSet());
        Set<String> allHierarchyNumbers = productHierarchyService.getAllHierarchy();

        if (!allHierarchyNumbers.containsAll(hierarchyNumbers)) {
            hierarchyNumbers.removeAll(allHierarchyNumbers);
            throw new BytzBootException("以下Hierarchy不存在，请修改后重试" + hierarchyNumbers);
        }

        // delFlag为1的批量删除
        Set<String> deleteProducts = productExcels.stream()
                .filter(excel -> CommonConstant.DEL_FLAG_1.equals(excel.getDelFlag()))
                .map(ProductExcel::getProductNumber).collect(Collectors.toSet());
        if (CollectionUtil.isNotEmpty(deleteProducts)) {
            lambdaUpdate().in(Product::getProductNumber, deleteProducts).remove();
        }
        List<Product> products = BeanUtil.copyToList(insertOrUpdateExcels, Product.class, CopyOptions.create().setIgnoreProperties(Product::getDelFlag));

        // 给各种id赋值
        Map<String, String> lineCodeIdMap = lineService.list().stream()
                .collect(Collectors.toMap(ProductLine::getProductLineCode, ProductLine::getId));

        // 不同产品线的优惠分类可能重名，key使用产品线id+分类名
        Map<String, String> categoryNameIdMap = discountCategoryService.list().stream()
                .collect(Collectors.toMap(category -> category.getProductLineId() + category.getCategoryName(), ProductDiscountCategory::getId));

        products.forEach(product -> {

            String lineId = lineCodeIdMap.get(product.getProductLineCode());
            if (lineId == null) {
                throw new BytzBootException(String.format("找不到【%s】对应的产品线", product.getProductLineCode()));
            }
            product.setProductLineId(lineId);
            product.setProductLineName(product.getProductLineCode());

            String categoryId = categoryNameIdMap.get(lineId + product.getDiscountCategoryName());
            if (categoryId == null) {
                throw new BytzBootException(String.format("找不到产品线:【%s】【%s】对应的优惠分类", product.getProductLineCode(), product.getDiscountCategoryName()));
            }
            product.setDiscountCategoryId(categoryId);
        });

        EntityMergeInfoV2<Product> mergeInfo = MergeEntityUtil.calculateEntityMergeInfo(
                products,
                list(),
                MergeEntityOptions.<Product>builder().keyExtractor(Product::getProductNumber).build()
        );

        // 判断是否在ec清单中
        List<String> addNumbers = mergeInfo.getAddEntities().stream().map(Product::getProductNumber).collect(Collectors.toList());
        Set<String> ecProducts = ecProductService.getByProductNumbers(addNumbers);
        mergeInfo.getAddEntities().forEach(product -> {
            if (ecProducts.contains(product.getProductNumber())) {
                product.setIsEc(ProductConstants.ProductIsEC.YES);
            } else {
                product.setIsEc(ProductConstants.ProductIsEC.NO);
            }
        });

        saveBatch(mergeInfo.getAddEntities());
        updateBatchById(mergeInfo.getUpdateEntities());

        return null;
    }

    @Override
    public Boolean changeStatus(String id, String status) {
        return lambdaUpdate()
                .eq(Product::getId, id)
                .set(Product::getStatus, status)
                .update();
    }

    @Override
    public void export(HttpServletResponse response) throws IOException {
        List<ProductExcel> productExcels = BeanUtil.copyToList(list(), ProductExcel.class);
        ExcelUtil.export("商品列表", ProductExcel.class, response, productExcels);
    }

    @Override
    public List<String> searchProductNumber(String code) {

        if (StringUtils.isBlank(code)) {
            return new ArrayList<>();
        }

        return lambdaQuery()
                .likeRight(Product::getProductNumber, code)
                .eq(Product::getStatus, ProductConstants.ProductStatus.ENABLE)
                .last("LIMIT 10")
                .list()
                .stream().map(Product::getProductNumber)
                .collect(Collectors.toList());
    }

    @Override
    public Product getByNumber(String code) {
        return lambdaQuery()
                .eq(Product::getProductNumber, code)
                .one();
    }

    @Override
    protected Product insertSaveObject(Product saveRo) {
        return null;
    }

    @Override
    protected Product updateSaveObject(Product saveRo) {
        productChangeService.saveChangeHistory(saveRo);
        updateById(saveRo);
        return saveRo;
    }

    @Override
    protected Product saveOthers(Product saveRo) {
        return null;
    }

    @Override
    protected boolean deleteEntity(Product entity) {
        return removeById(entity);
    }

    @Override
    protected void deleteOthers(Product entity) {

    }

    @Override
    public Boolean importChange(List<Product> productList) {
        MergeEntityOptions<Product> options = MergeEntityOptions.<Product>builder()
                .keyExtractor(Product::getProductNumber)
                .updateEntityMerger((updateProduct, dbProduct) -> {
                    updateProduct.setId(dbProduct.getId());
                    return updateProduct;
                }).build();

        EntityMergeInfoV2<Product> mergeInfo = MergeEntityUtil.calculateEntityMergeInfo(productList, list(), options);
        return updateBatchById(mergeInfo.getUpdateEntities());
    }

    @Override
    public IPage<ProductModel> queryPage(String resellerId, Page<Object> page, Product product, Map<String, String[]> parameterMap) throws Exception {

        MPJLambdaWrapperEx<Product> queryWrapper = MPJQueryGenerator.initQueryWrapper(product, parameterMap, Product.class);
        // 获取商品状态为上架，并且基准价大于0的
        IPage<Product> productPage = baseMapper.selectJoinPage(page, Product.class, queryWrapper
                        .selectAll(Product.class)
                        .gt(Product::getBasePrice, BigDecimal.valueOf(0))
                        .eq(Product::getStatus, ProductConstants.ProductStatus.ENABLE)
        );

        List<Product> productList = productPage.getRecords();
        List<ProductModel> productModels = new ArrayList<>();

        int batchSize = 1000; // 每批次的商品数量
        for (int i = 0; i < productList.size(); i += batchSize) {
            List<Product> batch = productList.subList(i, Math.min(i + batchSize, productList.size()));
            productModels.addAll(calcPrice(resellerId, batch));
        }

        IPage<ProductModel> result = new Page<>();
        BeanUtils.copyProperties(productPage, result);

        result.setRecords(productModels);

        return result;
    }

    /**
     * 商品数据量比较大分批读取并写入excel
     */
    @Override
    public void exportResellerProducts(String resellerId,Product product, Map<String, String[]> parameterMap, HttpServletResponse response) throws Exception {


        // 构建excelWriter和writeSheet
        ExcelWriter excelWriter = ExcelUtil.constructWrite("经销商商品列表.xlsx", ProductModelExcel.class, response);
        WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").build();

        int pageSize = 1000; // 每页的商品数量
        int currentPage = 1;

        // 构建queryWrapper
        MPJLambdaWrapperEx<Product> queryWrapper = MPJQueryGenerator.initQueryWrapper(product, parameterMap, Product.class);
        queryWrapper.selectAll(Product.class)
                .gt(Product::getBasePrice, BigDecimal.valueOf(0))
                .eq(Product::getStatus, ProductConstants.ProductStatus.ENABLE);

        // 是否有数据
        boolean hasMoreData = true;

        // 分批查询并写入excel
        while (hasMoreData) {
            IPage<Product> productPage = new Page<>(currentPage, pageSize, false);
            IPage<Product> resultPage = baseMapper.selectJoinPage(productPage, Product.class, queryWrapper);
            List<Product> productList = resultPage.getRecords();

            if (productList.isEmpty()) {
                hasMoreData = false;
                continue;
            }

            // 计算价格
            List<ProductModel> productModels = calcPrice(resellerId, productList);
            List<ProductModelExcel> excelList = BeanUtil.copyToList(productModels, ProductModelExcel.class);
            // 写入
            excelWriter.write(excelList, writeSheet);

            currentPage++;
        }
        // 完成写入关闭资源
        excelWriter.finish();
        response.getOutputStream().flush();
        response.getOutputStream().close();
    }


    /**
     * 计算商品价格
     * @param products 商品列表
     * @return 商品model
     */
    private List<ProductModel> calcPrice(String resellerId, List<Product> products) {


        List<ProductModel> modelList = BeanUtil.copyToList(products, ProductModel.class);
        // 计算价格
        Map<String, PriceComputeResult> priceResult = resellerCmsManager.getProductPriceManager().compute(resellerId, products);
        // 获取产品分类
        List<String> hierrarchNumbers = modelList.stream().map(ProductModel::getHierarchyNumber).collect(Collectors.toList());
        Map<String, ProductHierarchy> hierarchyMap = productHierarchyService.getByHierarchyNumbers(hierrarchNumbers).stream()
                .collect(Collectors.toMap(ProductHierarchy::getHierarchyNumber, e -> e));

        for (ProductModel productModel : modelList) {
            // 设置预付比例
            ProductHierarchy hierarchy = hierarchyMap.get(productModel.getHierarchyNumber());
            productModel.setPrepayRatio(hierarchy.getPrepayRatio());
            // 设置价格
            PriceComputeResult price = priceResult.get(productModel.getProductNumber());
            if (price != null) {
                productModel.setCalculatePrice(price.getPrice());
            }
        }

        return modelList;
    }

}